﻿using System;
using System.ComponentModel;
using System.Drawing;
using System.Timers;
using System.Windows.Forms;
using MessageTools;

namespace MessageBar
{
    [ToolboxBitmap(typeof(MessageBar), "MessageBar.png")]
    public class MessageBar : DisplayUnit
    {
        public MessageBar()
        {
            InitializeComponent();
            InitMore();
        }
        public override void UpdateLook()
        {
            StopCarousel();
            TextLabel.Text = MessageText;
            if (AttachedMessage != null)
            {
                base.BackColor = BackColor;
                try
                {
                    if (UseColorset)
                        base.BackColor = Colorset[Level];
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
                IconBox.Image = null;
                try
                {
                    IconBox.Image = Icons[Level];
                }
                catch (Exception ex)
                {
                    MessageBox.Show(ex.ToString());
                }
            }
            else
            {
                base.BackColor = BackColor;
                IconBox.Image = null;
            }
            Show();
            if (!Fixed)
                FadeMove(1);
            else
                base.Location = StartPosition;
        }
        private void UpdateLayout()
        {
            if (!ShowIcon)
                IconBox.Location = new Point(-IconBox.Width, 0);
            else
                IconBox.Location = new Point(IconBoxOffset.X, (Height - IconBox.Height) / 2 + IconBoxOffset.Y);
            TextLabel.Location = new Point(IconBox.Location.X + IconBox.Width + TextLabelOffset.X, (Height - TextLabel.Height) / 2 + TextLabelOffset.Y);
        }
        private void InitializeComponent()
        {
            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MessageBar));
            this.CloseButton = new System.Windows.Forms.PictureBox();
            this.IconBox = new System.Windows.Forms.PictureBox();
            this.TextLabel = new System.Windows.Forms.Label();
            ((System.ComponentModel.ISupportInitialize)(this.CloseButton)).BeginInit();
            ((System.ComponentModel.ISupportInitialize)(this.IconBox)).BeginInit();
            this.SuspendLayout();
            // 
            // CloseButton
            // 
            this.CloseButton.BackColor = System.Drawing.Color.Transparent;
            this.CloseButton.Image = ((System.Drawing.Image)(resources.GetObject("CloseButton.Image")));
            this.CloseButton.Location = new System.Drawing.Point(579, 3);
            this.CloseButton.Name = "CloseButton";
            this.CloseButton.Size = new System.Drawing.Size(15, 15);
            this.CloseButton.SizeMode = System.Windows.Forms.PictureBoxSizeMode.CenterImage;
            this.CloseButton.TabIndex = 0;
            this.CloseButton.TabStop = false;
            this.CloseButton.Click += new System.EventHandler(this.CloseButton_Click);
            this.CloseButton.MouseLeave += new System.EventHandler(this.CloseButton_MouseLeave);
            this.CloseButton.MouseMove += new System.Windows.Forms.MouseEventHandler(this.CloseButton_MouseMove);
            // 
            // IconBox
            // 
            this.IconBox.BackColor = System.Drawing.Color.Transparent;
            this.IconBox.Image = global::MessageBar.Properties.Resources.succeed;
            this.IconBox.Location = new System.Drawing.Point(3, 2);
            this.IconBox.Name = "IconBox";
            this.IconBox.Size = new System.Drawing.Size(20, 20);
            this.IconBox.SizeMode = System.Windows.Forms.PictureBoxSizeMode.Zoom;
            this.IconBox.TabIndex = 1;
            this.IconBox.TabStop = false;
            // 
            // TextLabel
            // 
            this.TextLabel.AutoSize = true;
            this.TextLabel.BackColor = System.Drawing.Color.Transparent;
            this.TextLabel.Font = new System.Drawing.Font("微软雅黑", 10F);
            this.TextLabel.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(40)))), ((int)(((byte)(40)))), ((int)(((byte)(40)))));
            this.TextLabel.Location = new System.Drawing.Point(28, 2);
            this.TextLabel.Name = "TextLabel";
            this.TextLabel.Size = new System.Drawing.Size(65, 20);
            this.TextLabel.TabIndex = 2;
            this.TextLabel.Text = "默认消息";
            this.TextLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
            // 
            // MessageBar
            // 
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None;
            this.BackColor = System.Drawing.SystemColors.ControlLight;
            this.Controls.Add(this.TextLabel);
            this.Controls.Add(this.IconBox);
            this.Controls.Add(this.CloseButton);
            this.Font = new System.Drawing.Font("微软雅黑", 10.5F);
            this.MinimumSize = new System.Drawing.Size(100, 10);
            this.Name = "MessageBar";
            this.Size = new System.Drawing.Size(596, 25);
            ((System.ComponentModel.ISupportInitialize)(this.CloseButton)).EndInit();
            ((System.ComponentModel.ISupportInitialize)(this.IconBox)).EndInit();
            this.ResumeLayout(false);
            this.PerformLayout();

        }
        private void InitMore()
        {
            /**允许非创建线程调用（不安全）*/
            //CheckForIllegalCrossThreadCalls = false;
            #region 布局初始化
            //示例图标
            IconBox.Image = Properties.Resources.succeed;
            ShowIcon = true;
            CloseButton.BackColor = Color.FromArgb(0, 220, 220, 220);
            CloseButton.Visible = !Fixed;
            TempIconBoxLocation = IconBox.Location;
            #endregion
            #region 设置消息栏FadeIn/Out的Timer
            FadeTimer.AutoReset = true;
            FadeTimer.Interval = FadeTime / FPS;
            FadeTimer.Elapsed += FadeTimer_Elapsed;
            #endregion
            #region 设置关闭按钮渐变高亮特效的Timer
            HiLightTimer.AutoReset = true;
            HiLightTimer.Interval = 20;
            HiLightTimer.Elapsed += HiLightTimer_Elapsed;
            MaxA = 210;
            #endregion
            #region 设置轮播Timer
            CarouselTimer.AutoReset = true;
            CarouselTimer.Elapsed += CarouselTimer_Elapsed;
            #endregion
        }
        private PictureBox CloseButton = new PictureBox();
        #region Timer声明
        private System.Timers.Timer FadeTimer = new System.Timers.Timer();
        private System.Timers.Timer HiLightTimer = new System.Timers.Timer();
        private System.Timers.Timer CarouselTimer = new System.Timers.Timer();
        #endregion
        #region 属性、字段
        [Description("消息栏相对于其容器左上角的初始位置。"), Category("布局")]
        public new Point Location
        {
            get { return base.Location; }
            set
            {
                StartPosition = value;
                EndPosition = new Point(StartPosition.X, StartPosition.Y + Height);
                if (isShowing)
                    base.Location = StartPosition;
                else
                    base.Location = EndPosition;
            }
        }
        [Description("控件的大小(以像素为单位)。"), Category("布局")]
        public new Size Size
        {
            get { return base.Size; }
            set
            {
                base.Size = value;
                EndPosition = new Point(StartPosition.X, StartPosition.Y + Height);
                IconScale = IconScale;
                CloseButton.Location = new Point(Width - 2 - CloseButton.Width, 3);
            }
        }
        [Browsable(false)]
        public new int Height
        {
            get { return base.Height; }
            set
            {
                base.Height = value;
                EndPosition = new Point(StartPosition.X, StartPosition.Y + Height);
                IconScale = IconScale;
            }
        }
        [Browsable(false)]
        public new int Width
        {
            get { return base.Width; }
            set
            {
                base.Width = value;
                CloseButton.Location = new Point(Width - 2 - CloseButton.Width, 3);
            }
        }
        private Color backColor = Color.FromArgb(220, 220, 220, 220);
        [Description("不启用背景颜色集合时默认的背景颜色。"), Category("外观")]
        public new Color BackColor
        {
            get { return backColor; }
            set
            {
                backColor = value;
                UpdateLook();
            }
        } 
        public new static Font DefaultFont = new Font("微软雅黑", 10);
        [Description("根据消息等级所显示的背景颜色的集合。"), Category("消息显示")]
        public Color[] Colorset { get; set; } = {
            Color.FromArgb(30, 160, 0),
            Color.FromArgb(0, 122, 204),
            Color.FromArgb(202, 81, 0),
            Color.FromArgb(180, 0, 0) };
        public bool useColorset = false;
        [Description("是否根据消息等级改变背景颜色。"), Category("消息显示")]
        public bool UseColorset
        {
            get { return useColorset; }
            set
            {
                useColorset = value;
                if (UseColorset)
                    base.BackColor = Colorset[Level];
                else
                    base.BackColor = BackColor;
            }
        }
        private string messageText = "示例消息";
        [Description("消息文本。"), Category("消息显示"), DefaultValue("默认消息")]
        public override string MessageText
        {
            get { return messageText; }
            set
            {
                messageText = value;
                TextLabel.Text = MessageText;
            }
        }
        public override Font Font
        {
            get { return TextLabel.Font; }
            set
            {
                TextLabel.Font = value;
                UpdateLayout();
            }
        }
        private Point textLabelOffset = new Point(0, 0);
        [Description("微调消息文本位置的偏移量。"), Category("布局")]
        public Point TextLabelOffset
        {
            get { return textLabelOffset; }
            set
            {
                textLabelOffset = value;
                UpdateLayout();
            }
        }
        public override Color ForeColor
        {
            get { return TextLabel.ForeColor; }
            set
            {
                TextLabel.ForeColor = value;
            }
        }
        [Description("根据消息等级所显示的图标的集合。"), Category("消息显示")]
        public Image[] Icons { get; set; } = {
            Properties.Resources.succeed, Properties.Resources.info,
            Properties.Resources.warning, Properties.Resources.error
        };
        private Point TempIconBoxLocation;
        private float iconScale = 0.7F;
        [Description("图标边长与消息栏高度的比例。"), Category("外观")]
        public float IconScale
        {
            get { return iconScale; }
            set
            {
                if (value > 1 || value <= 0)
                    throw new ArgumentException("属性值无效，请输入一个大于0且小于等于1的值");
                else
                {
                    iconScale = value;
                    IconBox.Size = new Size((int)(Height * IconScale), (int)(Height * IconScale));
                    UpdateLayout();
                }
            }
        }
        private Point iconBoxOffset = new Point(3, 0);
        [Description("微调消息图标位置的偏移量。"), Category("布局")]
        public Point IconBoxOffset
        {
            get { return iconBoxOffset; }
            set
            {
                iconBoxOffset = value;
                UpdateLayout();
            }
        }
        private bool showIcon;
        [Description("是否显示图标。"), Category("消息显示")]
        public bool ShowIcon
        {
            get { return showIcon; }
            set
            {
                showIcon = value;
                UpdateLayout();
            }
        }
        private bool isfixed = true;
        [Description("指定消息栏显示类型，True：固定消息栏，False：弹出式消息栏。"), Category("行为")]
        public bool Fixed
        {
            get { return isfixed; }
            set
            {
                isfixed = value;
                CloseButton.Visible = !Fixed;
                if (value)
                    isShowing = true;
            }
        }
        [Description("当消息栏为弹出式消息栏时，淡入淡出动作的时间。"), Category("动画")]
        public int FadeTime { get; set; } = 1000;
        public static readonly int FPS = 200;
        [Description("消息栏轮播字符串的集合。"), Category("动画")]
        public string[] CarouselText { get; set; } = null;
        [Description("消息栏轮播的频率。"), Category("动画")]
        public double CarouselFrequency { get; set; } = 2;
        private int currentTextIndex;
        private int CurrentTextIndex
        {
            get { return currentTextIndex; }
            set
            {
                currentTextIndex = value;
                TextLabel.Text = CarouselText[CurrentTextIndex];
            }
        }
        private int level;
        public override int Level
        {
            get { return level; }
            set
            {
                if (value > MaxLevel || value < 0)
                    throw new LevelOutOfRangeException("消息等级范围超限");
                else
                {
                    level = value;
                    if (ShowIcon)
                        IconBox.Image = Icons[Level];
                    if (UseColorset)
                    {
                        try { base.BackColor = Colorset[Level]; }
                        catch (Exception) { }
                    }
                }
            }
        }
        private bool isShowing = true;
        private bool IsShowing
        {
            get { return isShowing; }
            set
            {
                if (Fixed)
                    isShowing = true;
                else
                    isShowing = value;
            }
        }
        #endregion
        #region 关闭按钮高亮渐变
        private int HiLightStep;
        private PictureBox IconBox;
        private Label TextLabel;
        private int MaxA;
        private void HiLightTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            int a = CloseButton.BackColor.A + HiLightStep;
            if (a < 0)
                a = 0;
            else if (a > MaxA)
                a = MaxA;
            CloseButton.BackColor = Color.FromArgb(a, 240, 240, 240);
            if (a == 0 || a == MaxA)
                HiLightTimer.Stop();
        }
        private void CloseButton_MouseMove(object sender, MouseEventArgs e)
        {
            HiLightStep = 8;
            HiLightTimer.Start();
        }
        private void CloseButton_MouseLeave(object sender, EventArgs e)
        {
            HiLightStep = -8;
            HiLightTimer.Start();
        }
        private void CloseButton_Click(object sender, EventArgs e)
        {
            FadeMove(-1);
        }
        #endregion
        #region 消息栏淡入淡出
        private Point StartPosition;
        private Point EndPosition;
        private Point TargetPosition;
        private int DeltaY;
        private void FadeTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            MoveALittle();
        }
        private void MoveALittle()
        {
            Action invokeAction = new Action(MoveALittle);
            if (InvokeRequired)
                Invoke(invokeAction);
            else
            {
                int NewY = Location.Y - DeltaY;
                if (NewY < StartPosition.Y || NewY > StartPosition.Y + Height + 1)
                    NewY = TargetPosition.Y;
                base.Location = new Point(StartPosition.X, NewY);
                if (Location.Y == TargetPosition.Y)
                {
                    FadeTimer.Stop();
                    isShowing = TargetPosition == StartPosition;
                }
            }
        }
        /**direction：1为淡入，-1为淡出*/
        private void FadeMove(int direction)
        {
            if (Math.Abs(direction) != 1)
                throw new UndefinedMoveDirectionExceptation();
            DeltaY = (Height / FPS + 1) * direction;
            base.Location = direction == 1 ? EndPosition : StartPosition;
            TargetPosition = direction == -1 ? EndPosition : StartPosition;
            Show();
            FadeTimer.Start();
        }
        #endregion
        #region 轮播文字
        private void CarouselTimer_Elapsed(object sender, ElapsedEventArgs e)
        {
            if (TextLabel.InvokeRequired)
                Invoke(new Action(() => { CurrentTextIndex = (CurrentTextIndex + 1) % CarouselText.Length; }));
            else
                CurrentTextIndex = (CurrentTextIndex + 1) % CarouselText.Length;
        }
        public void StartCarousel(int Level)
        {
            Action<int> invokeAction = StartCarousel;
            if (TextLabel.InvokeRequired)
                TextLabel.Invoke(invokeAction, Level);
            else
            {
                try
                {
                    if (CarouselText != null)
                    {
                        CarouselTimer.Interval = 1000 / CarouselFrequency;
                        Hide();
                        this.Level = Level;
                        Fixed = true;
                        base.Location = StartPosition;
                        CurrentTextIndex = 0;
                        Show();
                        CarouselTimer.Start();
                    }
                    else throw new NullReferenceException("未指定轮播文本集合的实例");
                }
                catch (ArgumentOutOfRangeException) { throw new ArgumentOutOfRangeException("文本轮播的频率必须大于0"); }
            }
        }
        public void StopCarousel()
        {
            try { CarouselTimer.Close(); }
            catch (Exception) { }
        }
        #endregion
    }
}